#include "productTable.h"
#include "version.h"
#include "cJSON.h"
#include "logger.h"
#include "db.h"
#include <string.h>
#include <stdlib.h>

/**
 *  
 */
#define PRODUCT_TABLE_NAME "t_product"
#define SQL_PRODUCT_TABLE_CREATE "CREATE TABLE IF NOT EXISTS " PRODUCT_TABLE_NAME " (id INT PRIMARY KEY NOT NULL, classify INT, name TEXT NOT NULL, model TEXT NOT NULL, manufacturer TEXT NOT NULL, manuId TEXT NOT NULL, protocol TEXT NOT NULL, protocolID TEXT NOT NULL, desc CHAR(256))"
#define SQL_PRODUCT_TABLE_INSERT(...) "INSERT INTO " PRODUCT_TABLE_NAME "(id, classify, name, model, manufacturer, manuId, protocol, protocolID, desc) VALUES (" #__VA_ARGS__ ")"
#define SQL_PRODUCT_TABLE_REPLACE(...) "REPLACE INTO " PRODUCT_TABLE_NAME "(id, classify, name, model, manufacturer, manuId, protocol, protocolID, desc) VALUES (" #__VA_ARGS__ ")"
#define SQL_PRODUCT_TABLE_DELETE(id) "DELETE FROM " PRODUCT_TABLE_NAME " WHERE id = " #id
#define SQL_PRODUCT_TABLE_SELECT(id) "SELECT * FROM " PRODUCT_TABLE_NAME " WHERE id = " #id



/*===============================================================*/
/* 模型 */
char* getProtocolStr(T_PRODUCT* product){
    if(NULL == product){
        log_file_e(APPNAME, "getProtocolStr: product is NULL");
        return NULL;
    }

    cJSON* root = cJSON_CreateArray();
    if(NULL == root){
        log_file_e(APPNAME, "getProtocolStr: cJSON_CreateArray failed");
        return NULL;
    }
    for(int i = 0; i < 8; i++){
        if(0 == product->protocol[i]){
            break;
        }
        cJSON_AddItemToArray(root, cJSON_CreateNumber(product->protocol[i]));
    }
    char* str = cJSON_Print(root);
    cJSON_Delete(root);
    return str;
}

char* getProtocolIDStr(T_PRODUCT* product){
    if(NULL == product){
        log_file_e(APPNAME, "getProtocolIDStr: product is NULL");
        return NULL;
    }

    cJSON* root = cJSON_CreateArray();
    if(NULL == root){
        log_file_e(APPNAME, "getProtocolIDStr: cJSON_CreateArray failed");
        return NULL;
    }
    for(int i = 0; i < 8; i++){
        if(NULL == product->protocolID[i]){
            break;
        }
        cJSON* sub = cJSON_CreateArray();
        for(int j = 0; j < 64; j++){
            if(0 == product->protocolID[i][j]){
                break;
            }
            cJSON_AddItemToArray(sub, cJSON_CreateNumber(product->protocolID[i][j]));
        }
        // cJSON* item = cJSON_CreateObject();
        // cJSON_AddItemToObject(item, "index", i);
        // cJSON_AddItemToObject(item, "protocolID", sub);
        // cJSON_AddItemToArray(root, item);
        cJSON_AddItemToArray(root, sub);
    }
    char* str = cJSON_Print(root);
    cJSON_Delete(root);
    return str;
}

void getProtocol(const char* protocolStr, T_PRODUCT* product){
    if((NULL == protocolStr) || (NULL == product)){
        log_file_e(APPNAME, "getProtocol: protocolStr or product is NULL");
        return;
    }
    cJSON* root = cJSON_Parse(protocolStr);
    if(NULL == root){
        log_file_e(APPNAME, "getProtocol: cJSON_Parse failed");
        return;
    }
    int i = 0;
    if(cJSON_IsArray(root)){
        cJSON* item = NULL;
        for(int i = 0; i < cJSON_GetArraySize(root); i++){
            item = cJSON_GetArrayItem(root, i);
            if(cJSON_IsNumber(item)){
                product->protocol[i] = item->valueint;
            }
        }
    }
}

void getProtocolID(const char* protocolIDStr, T_PRODUCT* product){
    if((NULL == protocolIDStr) || (NULL == product)){
        log_file_e(APPNAME, "getProtocolID: protocolIDStr or product is NULL");
        return;
    }
    cJSON* root = cJSON_Parse(protocolIDStr);
    if(NULL == root){
        log_file_e(APPNAME, "getProtocolID: cJSON_Parse failed");
        return;
    }
    int i = 0;
    if(cJSON_IsArray(root)){
        cJSON* item = NULL;
        for(int i = 0; i < cJSON_GetArraySize(root); i++){
            item = cJSON_GetArrayItem(root, i);
            if(cJSON_IsArray(item)){
                for(int j = 0; j < cJSON_GetArraySize(item); j++){
                    cJSON* sub = cJSON_GetArrayItem(item, j);
                    if(cJSON_IsNumber(sub)){
                        product->protocolID[i][j] = sub->valueint;
                    }
                }
            }
        }
    }
}
int createProductTable(){
    return db_create_table(SQL_PRODUCT_TABLE_CREATE);
}

int insertProduct(T_PRODUCT* product){
    if(NULL == product){
        log_file_e(APPNAME, "insert product is NULL");
        return -1;
    }
    if((NULL == product->name) || (1 > strlen(product->name))){
        log_file_e(APPNAME, "insert product name is NULL or empty");
        return -1;
    }
    char* protocol = getProtocolStr(product);
    char* protocolID = getProtocolIDStr(product);
    int ret = db_insert(SQL_PRODUCT_TABLE_INSERT(product->id, product->classify, product->name, product->manufacturer, product->manuId, protocol, protocolID, product->desc));
    cJSON_free(protocol);
    cJSON_free(protocolID);
    return ret;
}

int replaceProduct(T_PRODUCT* product){
    if(NULL == product){
        log_file_e(APPNAME, "replace product is NULL");
        return -1;
    }
    if((NULL == product->name) || (1 > strlen(product->name))){
        log_file_e(APPNAME, "replace product name is NULL or empty");
        return -1;
    }
    char* protocol = getProtocolStr(product);
    char* protocolID = getProtocolIDStr(product);
    int ret = db_insert(SQL_PRODUCT_TABLE_REPLACE(product->id, product->classify, product->name, product->manufacturer, product->manuId, protocol, protocolID, product->desc));
    cJSON_free(protocol);
    cJSON_free(protocolID);
    return ret;
}

int deleteProduct(T_PRODUCT* product){
    if(NULL == product){
        log_file_e(APPNAME, "delete product is NULL");
        return -1;
    }
    return db_delete(SQL_PRODUCT_TABLE_DELETE(product->id));
}
/**
 *  
 */
static int productCallback(void *data, int argc, char **argv, char **azColName){
    int i = 0;
    if(NULL == data){
        log_file_e(APPNAME, "productCallback data is NULL");
        return -1;
    }
    T_PRODUCT_LIST* productList = (T_PRODUCT_LIST*)data;
    if((0 == productList->count) || (NULL == productList->head)){
        productList->head = productList->tail = (T_PRODUCT*)malloc(sizeof(T_PRODUCT));
        productList->head->next = NULL;
        productList->head->prev = NULL;
    } else {
        productList->tail->next = (T_PRODUCT*)malloc(sizeof(T_PRODUCT));
        productList->tail->next->prev = productList->tail;
        productList->tail = productList->tail->next;
    }
    productList->count++;
    for(i = 0; i < argc; i++){
        if(0 == strcmp(azColName[i], "id")){
            productList->tail->id = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "classify")){
            productList->tail->classify = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "name")){
            if(NULL == argv[i]){
                productList->tail->name[0] = '\0';
            } else {
                strcpy(productList->tail->name, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "model")){
            if(NULL == argv[i]){
                productList->tail->model[0] = '\0';
            } else {
                strcpy(productList->tail->model, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "manufacturer")){
            if(NULL == argv[i]){
                productList->tail->manufacturer[0] = '\0';
            } else {
                strcpy(productList->tail->manufacturer, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "manuId")){
            if(NULL == argv[i]){
                productList->tail->manuId[0] = '\0';
            } else {
                strcpy(productList->tail->manuId, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "protocol")){
            if(NULL == argv[i]){
                memset(productList->tail->protocol, 0, sizeof(productList->tail->protocol));
            } else {
                getProtocol(argv[i], productList->tail);
            }
        } else if(0 == strcmp(azColName[i], "protocolID")){
            if(NULL == argv[i]){
                memset(productList->tail->protocolID, 0, sizeof(productList->tail->protocolID));
            } else {
                getProtocolID(argv[i], productList->tail);
            }
        } else if(0 == strcmp(azColName[i], "desc")){
            if(NULL == argv[i]){
                productList->tail->desc[0] = '\0';
            } else {
                strcpy(productList->tail->desc, argv[i]);
            }
        }
        log_i("%s = %s", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    return productList->count;
}

int selectProduct(const char* sql, T_PRODUCT_LIST* productList){
    if((NULL == sql) || (1 > strlen(sql)) || (NULL == productList)){
        log_file_e(APPNAME, "select product sql is NULL");
        return -1;
    }
    return db_select(sql, productCallback, productList);

}
//
void dbProductInit(){
    createProductTable();
}
